#include "Font.h"

#include <freetype/freetype.h>
#include <freetype/ftglyph.h>

#include "Font/Glyph.h"

#include "Containers/Tuple.h"
#include "Texture/Texture2D.h"

std::shared_ptr<SFreeTypeGlyph> RFont::FindOrCreateGlyph(char32_t InUnicode ,uint32_t InFontSize)
{
    auto Key=WH::MakeTuple(InUnicode,InFontSize);
    if(Glyphs.Contains(Key))
    {   
        return Glyphs[Key];
    }

    //there is two way to set font size,  FT_Set_Char_Size and FT_Set_Pixel_Sizes
    //set width=0, means the width is auto calculated
    auto Error=FT_Set_Pixel_Sizes((FT_Face)LowLevelFont,0,InFontSize); 

    auto CharIndex=FT_Get_Char_Index((FT_Face)LowLevelFont,(FT_ULong)(InUnicode));
    Error=FT_Load_Glyph((FT_Face)LowLevelFont,CharIndex,FT_LOAD_DEFAULT);

    FT_Glyph Glyph;
    Error=FT_Get_Glyph(FT_Face(LowLevelFont)->glyph,&Glyph);

    //convert to image
    {
        FT_Vector  origin;
        origin.x = 0;
        origin.y = 0;

        FT_Glyph_To_Bitmap(
            &Glyph
            ,FT_RENDER_MODE_NORMAL
            ,&origin
            ,1);/* destroy original image == true */
    }


    std::shared_ptr<SFreeTypeGlyph> NewGlyph=std::make_shared<SFreeTypeGlyph>(Glyph);
    
    NewGlyph->CodePoint=InUnicode;
    NewGlyph->FontSize=InFontSize;

    NewGlyph->AdvanceX=Glyph->advance.x>>16;
    NewGlyph->AdvanceY=Glyph->advance.y>>16;

    FT_BBox GlphyBox;
    FT_Glyph_Get_CBox(Glyph,FT_GLYPH_BBOX_PIXELS,&GlphyBox);
    NewGlyph->Box.Min.X=GlphyBox.xMin;
    NewGlyph->Box.Min.Y=GlphyBox.yMin;
    NewGlyph->Box.Extent.X=GlphyBox.xMax-GlphyBox.xMin;
    NewGlyph->Box.Extent.Y=GlphyBox.yMax-GlphyBox.yMin;
    
    NewGlyph->Font=this;

    Glyphs.Add(Key,NewGlyph);

    return NewGlyph;
}

bool RFont::SupportChar(char32_t InUnicode)
{
    return 0!=FT_Get_Char_Index((FT_Face)LowLevelFont,(FT_ULong)(InUnicode));
    
}

float RFont::GetLineHeight(uint32_t InFontSize)
{
    auto Error=FT_Set_Pixel_Sizes((FT_Face)LowLevelFont,0,InFontSize);
    return FT_Face(LowLevelFont)->size->metrics.height>>6;
}

float RFont::GetAscent(uint32_t InFontSize)
{
    auto Error=FT_Set_Pixel_Sizes((FT_Face)LowLevelFont,0,InFontSize);
    return FT_Face(LowLevelFont)->size->metrics.ascender>>6;
}

float RFont::GetDescent(uint32_t InFontSize)
{
    auto Error=FT_Set_Pixel_Sizes((FT_Face)LowLevelFont,0,InFontSize);
    return FT_Face(LowLevelFont)->size->metrics.descender>>6;
}

